package org.codetranslators.compiler.tiger.semantics;

import org.codetranslators.compiler.tiger.abssyntree.Symbol;

public class Environments {

	private Table variableAndFunctionTable;
	private Table typeTable;
	private Table escapeTable;
	
	private Level topLevel;
	
	public Environments(Level topLevel)
	{
		this.topLevel = topLevel;
		
		// Initialize the two symbol tables - one for the variable, the other the type
		variableAndFunctionTable = new Table();
		typeTable = new Table();
		escapeTable = new Table();
		
		//Initialize typeTable with predefined ids (int and string)
		typeTable.put(Symbol.symbol("int"), IntTypeEntry.getInstance());
		typeTable.put(Symbol.symbol("string"), StringTypeEntry.getInstance());
		typeTable.put(Symbol.symbol("void"), VoidTypeEntry.getInstance());
		
		//Initialize variableAndFunction table with predefined functions (print, flush, ord, etc.)
		
		// Entry for the print function - one param s:string and void return value
		
		TypeEntry stringtpEntry = (TypeEntry) typeTable.get(Symbol.symbol("string"));
		RecordTypeEntry printFuncParams = new RecordTypeEntry(Symbol.symbol("s"), stringtpEntry, null);
		
		TypeEntry inttpEntry = (TypeEntry) typeTable.get(Symbol.symbol("int"));
		RecordTypeEntry intFuncParams = new RecordTypeEntry(Symbol.symbol("i"), inttpEntry, null);
		
		TypeEntry retTypeEntry = (TypeEntry)        // The return type of the function which is void
				typeTable.get(Symbol.symbol("void"));	
		makeFunctionEntry("print", printFuncParams, retTypeEntry); // make print function entry
		
		makeFunctionEntry("printInt", intFuncParams, retTypeEntry); // make print function entry
		
		// Entry for the flush function - both params and ret type are void; make null for params
		RecordTypeEntry flushFuncParams = new RecordTypeEntry(null, null, null);
		makeFunctionEntry("flush", flushFuncParams, retTypeEntry); // make print function entry
		
		// Entry for the getchar function - one param s:string and void return value
		RecordTypeEntry getcharFuncParams = new RecordTypeEntry(Symbol.symbol("s"), stringtpEntry, null);
		makeFunctionEntry("getchar", getcharFuncParams, retTypeEntry); // make getchar function entry
		
		// Entry for the ord function - one param s:string and int return value
		//TypeEntry inttpEntry = (TypeEntry) typeTable.get(Symbol.symbol("int"));
		RecordTypeEntry ordFuncParams = new RecordTypeEntry(Symbol.symbol("s"), stringtpEntry, null);
		makeFunctionEntry("ord", ordFuncParams, inttpEntry); // make ord function entry
		
		// Entry for the chr function - one param i:int and string return value
		RecordTypeEntry chrFuncParams = new RecordTypeEntry(Symbol.symbol("i"), inttpEntry, null);
		makeFunctionEntry("chr", chrFuncParams, stringtpEntry);
		
		// Entry for the size function - one param s:string and int return value
		RecordTypeEntry sizeFuncParams = new RecordTypeEntry(Symbol.symbol("s"), stringtpEntry, null);
		makeFunctionEntry("size", sizeFuncParams, inttpEntry);
		
		// Entry for the sustring function - string, int, int param values and an int return value
		RecordTypeEntry substringFuncParams1 = new RecordTypeEntry(Symbol.symbol("n"), inttpEntry, null);
		RecordTypeEntry substringFuncParams2 = new RecordTypeEntry(Symbol.symbol("first"), 
												inttpEntry, substringFuncParams1);
		RecordTypeEntry substringFuncParams = new RecordTypeEntry(Symbol.symbol("s"), 
												stringtpEntry, substringFuncParams2);
		makeFunctionEntry("substring", substringFuncParams, stringtpEntry);
		
		// Entry for the concat function - string, string param values and a string return value
		RecordTypeEntry concatFuncParams1 = new RecordTypeEntry(Symbol.symbol("s1"), stringtpEntry, null);
		RecordTypeEntry concatFuncParams = new RecordTypeEntry(Symbol.symbol("s2"), 
												stringtpEntry, concatFuncParams1);
		makeFunctionEntry("concat", concatFuncParams, stringtpEntry);
		
		// Entry for the not function - an int param value and an int return value
		RecordTypeEntry notFuncParams = new RecordTypeEntry(Symbol.symbol("i"), inttpEntry, null);
		makeFunctionEntry("not", notFuncParams, inttpEntry); // make not function entry
		
		// Entry for the exit function - an int param value and a void (or null) return value
		RecordTypeEntry exitFuncParams = new RecordTypeEntry(Symbol.symbol("i"), inttpEntry, null);
		makeFunctionEntry("exit", exitFuncParams, null); // make exit function entry
		
		// Entry for the printint function - an int param value and a void (or null) return value
		RecordTypeEntry printIntFuncParams = new RecordTypeEntry(Symbol.symbol("i"), inttpEntry, null);
		makeFunctionEntry("printint", printIntFuncParams, null); // make exit function entry
	}
	
	public Table getVariableTable()
	{
		return variableAndFunctionTable;
	}
	
	public Table getTypeTable()
	{
		return typeTable;
	}
	
	public Table getEscapeTable()
	{
		return escapeTable;
	}
	
	private void makeFunctionEntry(String functionName, RecordTypeEntry formals, 
								TypeEntry returnType)
	{
		FunctionEntry funcEntry = new FunctionEntry(formals, returnType, topLevel); 		// create the new	
		variableAndFunctionTable.put(Symbol.symbol(functionName), funcEntry); // function and make entry
	}
}
